#include "screen.h"
#include <windows.h>
#include <iostream>
#include <conio.h>
#include <math.h>

#define MaxMenuLength 15
#pragma warning(disable : 4996)
#pragma warning(disable : 4244)

COORD coord = {160, 60}, coord2 = {0, 0};	// Coordinates used for "blit" operations
SMALL_RECT write = {0, 0, 159,59};			// Region to write to


using namespace std;

void screen::gotoxy(int x,int y)
{
HANDLE console_handle;
COORD cursor_coord;
DWORD actual=0;

cursor_coord.X=x;
cursor_coord.Y=y;

console_handle= GetStdHandle( STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(console_handle,cursor_coord);
}

void screen::settextcolor(int color)
{
 HANDLE  hColor;	
 hColor = GetStdHandle (STD_OUTPUT_HANDLE);
 SetConsoleTextAttribute(hColor,color); 
}

void screen::puttext(char *s,int x,int y,int c)
{
gotoxy(x,y);
settextcolor(c);
cout<<s;
settextcolor(0x07);
}

void screen::puttext(int i,int x,int y,int c)
{
gotoxy(x,y);
settextcolor(c);
cout<<i;
settextcolor(0x07);
}

void screen::box(int x1,int y1,int x2,int y2)
{
for (int i=x1;i<x2;i++)
{
 gotoxy(i,y1);
 cout<<(char)LineX;
 gotoxy(i,y2);
 cout<<(char)LineX;
}

for (int i=y1;i<y2;i++)
{
 gotoxy(x1,i);
 cout<<(char)LineY;
 gotoxy(x2,i);
 cout<<(char)LineY;
}

gotoxy(x1,y1);
cout<<(char)Line1;
gotoxy(x2,y1);
cout<<(char)Line2;
gotoxy(x2,y2);
cout<<(char)Line3;
gotoxy(x1,y2);
cout<<(char)Line4;

}
int screen::menu(char **Arr,int size,int starti,char *Header,int StartY)
{
char ch;
int ind=starti,passindex=0,offset=0;

placemenu(Arr,size,StartY,starti,Header,0);
do
{

ch = getch();
 
if (ch==27 || ch==13)
	break;

if (ch==0,ch==72)
	{
		ind--;
		if (ind<0)
			ind=size-1;
		offset = (ind>MaxMenuLength-1)?(ind-(MaxMenuLength-1)):(0);
		placemenu(Arr,size,StartY,ind,Header,offset);
	}
if (ch==0,ch==80)	
	{
		ind++;
		if (ind>=size)
			ind = 0;

		offset = (ind>MaxMenuLength-1)?(ind-(MaxMenuLength-1)):(0);
		placemenu(Arr,size,StartY,ind,Header,offset);
	}

}
while(ch!=27 && ch!=13);

if (ch==27)
	return -1;
else
	return ind;

}

void screen::placemenu(char **Arr,int size,int ystart,int index,char *header,int offset)
{
	int maxstringlength;
	int x0,x1,y0,y1,i,j,xt;
	char tmpstr[50];
	int menusize;
	menusize = (size>MaxMenuLength)?(MaxMenuLength):(size);
	maxstringlength = getmaxmenulength(Arr,size)+2;
	x0 = 40-(maxstringlength/2) ;
	x1 = 40+(maxstringlength/2)+1 ;
	y0 = ystart -1;
    y1 = ystart + menusize;
	settextcolor(0x0007);
	box(x0,y0,x1,y1);
	for(i=0;i<menusize;i++)
	{
	strcpy(tmpstr,"");
	xt = 40 - (int)strlen(Arr[i+offset])/2 + 1;
	for(j=x0;j<xt-1;j++)
		strcat(tmpstr," ");
	strcat(tmpstr,Arr[i+offset]);
	for(j=xt+(int)strlen(Arr[i+offset]);j<x1;j++)
		strcat(tmpstr," ");

	gotoxy(x0+1,ystart+i);
	
	if ((index!=i+offset))
		settextcolor(0x0007);
	else
		settextcolor(0x0070);

	cout<<tmpstr;
	}

	if (strlen(header)>0)
	{
		y0=ystart-1;
		x0 = 40 - ((int)strlen(header)+4)/2 + 1;
		settextcolor(0x0e);
		gotoxy(x0,y0);
		cout<<"[ "<<header<<" ]";
	}

settextcolor(0x0007);
	
}

int screen::getmaxmenulength(char **A,int size)
{
int i;
int max=0;
for(i=0;i<size;i++)
  if ((int)strlen(A[i])>max)
	  max = (int)strlen(A[i]);

return max;
}
char *screen::readvalue(char *title,char *range,int masked,int maxsize,char *msg)
{
char *tmpstr=NULL,ch,i;
int count=0,x1,y1=13;

system("cls");
box(0,11,79,15);

if (msg!=NULL)
{
x1 = 40 - (int)strlen(msg) / 2 + 1;
puttext(msg,x1,y1+2,0x0c);
}

puttext(title,20,y1,0x0f);
x1 = (int)strlen(title) + 20;

//showcursor(TRUE);
tmpstr = new char[50];//(char*)malloc(sizeof(char)*50);
strcpy(tmpstr,"");
settextcolor(0x000c);// string red
do
{
ch=getch();
if (count<maxsize)
  if (strchr(range,ch)!=NULL)
	{	
		count++;
		//tmpstr = (char*)realloc(tmpstr,sizeof(char)*(count+1));
        tmpstr[count-1]=ch;
		tmpstr[count]=0;
		gotoxy(x1,y1);
		if (!masked) cout<<tmpstr;//printf("%s",tmpstr);
		else
			for(i=0;i<(int)strlen(tmpstr);i++)
				cout<<"*";//printf("*");
	}
 if (ch==8 && count>0)
   {
		count--;
		tmpstr[count]=' ';
		gotoxy(x1,y1);
		if (!masked)
			cout<<tmpstr;//printf("%s",tmpstr);
		else
		{
			for(i=0;i<(int)strlen(tmpstr)-1;i++)
				cout<<"*";//printf("*");
				cout<<" ";//printf(" ");
		}

		//tmpstr = (char*)realloc(tmpstr,sizeof(char)*(count+1));
		tmpstr[count]=0;
		gotoxy(x1,y1);
		if (!masked) cout<<tmpstr;//printf("%s",tmpstr);
		else
			for(i=0;i<(int)strlen(tmpstr);i++)
				cout<<"*";//printf("*");
   }

 if (ch==27)
	 //if(!AskYesNoQuestion("Are you want to exit ?"))
	 {
		 ch=0;
  		 gotoxy(x1+(int)strlen(tmpstr),y1);
		 settextcolor(0x000c);// string red
		 //showcursor(TRUE);
	 }
	 if (ch==13)
		 if ((int)strlen(tmpstr)>0)
			 break;

}

while (ch!=27);

//showcursor(FALSE);
settextcolor(0x07);
if (count==0 || ch==27)
{
	if (ch==27 && (int)strlen(tmpstr)>0)
		free(tmpstr);
	return NULL;
}
else
	return tmpstr;

}

void screen::cls()
{
	system("cls");
}

void screen :: AnimateBox(int x1,int y1,int width1,int height1,
					int x2,int y2,int width2,int height2,
					int steps,int delay)
{

float dx,dy,dxa,dya;
float dw,dh,dwa,dha;
CHAR_INFO *CH;

CH = PushScreen();

//box(x1,y1,x1 + width1,y1 + height1);
//box(x2,y2,x2 + width2,y2 + height2);

dx = (float)(x2 - x1) / steps;
dy = (float)(y2 - y1) / steps;

dh = (float)(height2 - height1) / steps;
dw = (float)(width2  - width1) / steps;


Sleep(delay);
for (int i=0;i<=steps;i++)
{

	dxa = x1 + (int)floor(i*dx + 0.5);
	dya = y1 + (int)floor(i*dy + 0.5);

	dha = (int)floor(i*dh + 0.5);
	dwa = (int)floor(i*dw + 0.5);

	boxex(NULL,dxa,dya,dxa + width1 + dwa,dya + height1 + dha,BT_TWO,0x0e,0x00);

	if (i==0 || i==steps)
		Sleep(delay*3);
	else
		Sleep(delay);

	PopScreen(CH,false);

}

PopScreen(CH,true);

}

void screen::PopScreen(CHAR_INFO *INFO,bool isfree)
{
HANDLE hnd;

hnd = GetStdHandle(STD_OUTPUT_HANDLE);

WriteConsoleOutputA(hnd, (const CHAR_INFO *)(INFO), coord, coord2, &write);
if (isfree)
	free(INFO);
}

CHAR_INFO* screen::PushScreen()
{
CHAR_INFO *I;
HANDLE hnd;

I = (CHAR_INFO*)malloc(sizeof(CHAR_INFO)*(60*160));
hnd = GetStdHandle(STD_OUTPUT_HANDLE);
ReadConsoleOutputA(hnd,(PCHAR_INFO)I,coord,coord2,&write);
return I;
}

void screen::fillascii(int x0,int y0,int x1,int y1,char chr,char clr)
{
HANDLE hnd;
CHAR_INFO buf[60*160];
int i,j;
hnd = GetStdHandle(STD_OUTPUT_HANDLE);
ReadConsoleOutputA(hnd,(PCHAR_INFO)&buf,coord,coord2,&write);

for(i=y0;i<=y1;i++)
        for(j=x0;j<=x1;j++)
        {
                buf[160*i + j].Char.UnicodeChar = chr;
                buf[160*i + j].Attributes = clr;
        }
WriteConsoleOutputA(hnd, (const CHAR_INFO *)(&buf), coord, coord2, &write);

}

void screen::boxex(char * title,int x1,int y1,int x2,int y2, boxType bt,
					  int foreground,int background)
{

settextcolor(foreground);
for (int i=x1;i<x2;i++)
{
	gotoxy(i,y1);
	if (bt==BT_ONE) cout<<(char)OLineX; if (bt==BT_TWO) cout<<(char)LineX; 
	gotoxy(i,y2);
	if (bt==BT_ONE) cout<<(char)OLineX; if (bt==BT_TWO) cout<<(char)LineX; 
}

for (int i=y1;i<y2;i++)
{
	gotoxy(x1,i);
	if (bt==BT_ONE) cout<<(char)OLineY; if (bt==BT_TWO) cout<<(char)LineY; 
	gotoxy(x2,i);
	if (bt==BT_ONE) cout<<(char)OLineY; if (bt==BT_TWO) cout<<(char)LineY; 
}

	gotoxy(x1,y1);
	if (bt==BT_ONE) cout<<(char)OLine1; if (bt==BT_TWO) cout<<(char)Line1; 
	gotoxy(x2,y1);
	if (bt==BT_ONE) cout<<(char)OLine2; if (bt==BT_TWO) cout<<(char)Line2; 
	gotoxy(x2,y2);
	if (bt==BT_ONE) cout<<(char)OLine3; if (bt==BT_TWO) cout<<(char)Line3; 
	gotoxy(x1,y2);
	if (bt==BT_ONE) cout<<(char)OLine4; if (bt==BT_TWO) cout<<(char)Line4; 
	
	if (title != NULL)
	{
		gotoxy((x1 + x2)/2 - (int)strlen(title) / 2,y1);
		settextcolor(0x0f);
		cout<<title;
	}

	if (background != 0x00)
		fillascii(x1+1,y1+1,x2-1,y2-1,' ',background);

}

void screen::showcursor(bool a)
{
HANDLE hConsoleOutput;
CONSOLE_CURSOR_INFO structCursorInfo;

hConsoleOutput = GetStdHandle( STD_OUTPUT_HANDLE );

structCursorInfo.dwSize = 10;
structCursorInfo.bVisible = a;

SetConsoleCursorInfo( hConsoleOutput,&structCursorInfo );
}

void screen::MaximizeConsole()
{
HANDLE hOut;
    COORD NewSBSize;
    SMALL_RECT DisplayArea = {0, 0, 0, 0};
	CONSOLE_SCREEN_BUFFER_INFO i;

    hOut = GetStdHandle(STD_OUTPUT_HANDLE);

    NewSBSize = GetLargestConsoleWindowSize(hOut);

	GetConsoleScreenBufferInfo(hOut,&i);

    SetConsoleScreenBufferSize(hOut,
                               NewSBSize);

    DisplayArea.Right   = NewSBSize.X - 1;
    DisplayArea.Bottom =  NewSBSize.Y - 1;
	
    SetConsoleWindowInfo(hOut,
                         TRUE,
                         &DisplayArea);

	char t[500];

	SetConsoleTitle(L"MyOS2");
	GetConsoleTitleA( t, 500 );     // retrieve the text

    HWND hwndConsole = FindWindowA( NULL, t );  // FindWindowA actually

	ShowWindow(hwndConsole,SW_MAXIMIZE);

}

void screen::MinimizeConsole()
{
HANDLE hOut;
    COORD NewSBSize;
    SMALL_RECT DisplayArea = {0, 0, 0, 0};

    hOut = GetStdHandle(STD_OUTPUT_HANDLE);

	NewSBSize.X = 80;
	NewSBSize.Y = 300;

    SetConsoleScreenBufferSize(hOut,
                               NewSBSize);

	char t[500];

	SetConsoleTitle(L"MyOS2");
	GetConsoleTitleA( t, 500 );     // retrieve the text

    HWND hwndConsole = FindWindowA( NULL, t );  // FindWindowA actually

	ShowWindow(hwndConsole,SW_NORMAL);

    DisplayArea.Right  = NewSBSize.X - 1;
    DisplayArea.Bottom =  24;
	
    SetConsoleWindowInfo(hOut,
                         TRUE,
                         &DisplayArea);

	NewSBSize.X = 80;
	NewSBSize.Y = 300;

    SetConsoleScreenBufferSize(hOut,
                               NewSBSize);
}

CHAR_INFO screen::getPixel(int x,int y)
{
CHAR_INFO tmp;
HANDLE hnd;
COORD c1 = {1, 1}, c2 = {0, 0};
SMALL_RECT w = {x, y, x,y};
hnd = GetStdHandle(STD_OUTPUT_HANDLE);
ReadConsoleOutputA(hnd,(PCHAR_INFO)&tmp,c1,c2,&w);
return tmp;
}